<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="coinfaces">

        <title>ES2015 类</title>

    <link rel="stylesheet" href="../theme/css/style.css">
    <link rel="stylesheet" href="../theme/css/pygments.css">



</head>

<body>
    <div class="content">
<h1>ES2015 类</h1>    <p>
        under
            <a href="../tags/javascript/">JavaScript</a>
    </p>
    <p>
        in <a href="../categories/uncategorized/">Uncategorized</a>
    </p>
    <p>Published: 2019-04-02</p>


    <!-- wp:heading -->

<h2>语法</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->

<p>类定义<strong>不会</strong>被提升到作用域开始处，类必须先定义再使用，这是类和函数在语法上的重要区别。</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->

<h3>构造函数</h3>
<!-- /wp:heading -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="err">class Rectangle {</span>
<span class="err">  constructor(height, width) {</span>
<span class="err">    this.height = height;</span>
<span class="err">    this.width = width;</span>
<span class="err">  }</span>
<span class="err">}</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>不再写在函数体内：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="err">function Rectangle(height, width) {</span>
<span class="err">  this.height = height;</span>
<span class="err">  this.width = width;</span>
<span class="err">}</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:heading {"level":3} -->

<h3>实例方法</h3>
<!-- /wp:heading -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="n">Rectangle</span> {
  <span class="n">constructor</span>(<span class="n">height</span>, <span class="n">width</span>) {
    <span class="n">this</span>.<span class="n">height</span> = <span class="n">height</span>;
    <span class="n">this</span>.<span class="n">width</span> = <span class="n">width</span>;
  }

  <span class="n">calcArea</span>() {
    <span class="k">return</span> <span class="n">this</span>.<span class="n">height</span> * <span class="n">this</span>.<span class="n">width</span>;
  }

  <span class="n">static</span> <span class="n">staticCalcArea</span>(<span class="n">r</span>) {
    <span class="k">return</span> <span class="n">r</span>.<span class="n">height</span> * <span class="n">r</span>.<span class="n">width</span>;
  }
}
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>可以直接在类定义里定义实例方法和类方法，比不使用类要方便：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="k">function</span> <span class="n">Rectangle</span><span class="p">(</span><span class="n">height</span><span class="p">,</span> <span class="n">width</span><span class="p">)</span> <span class="err">{</span>
  <span class="n">this</span><span class="p">.</span><span class="n">height</span> <span class="o">=</span> <span class="n">height</span><span class="p">;</span>
  <span class="n">this</span><span class="p">.</span><span class="n">width</span> <span class="o">=</span> <span class="n">width</span><span class="p">;</span>
<span class="err">}</span>

<span class="n">Rectangle</span><span class="p">.</span><span class="n">prototype</span><span class="p">.</span><span class="n">calcArea</span> <span class="o">=</span> <span class="k">function</span> <span class="p">()</span> <span class="err">{</span>
  <span class="k">return</span> <span class="n">this</span><span class="p">.</span><span class="n">height</span> <span class="o">*</span> <span class="n">this</span><span class="p">.</span><span class="n">width</span><span class="p">;</span>
<span class="err">}</span>

<span class="n">Rectangle</span><span class="p">.</span><span class="n">staticCalcArea</span>  <span class="o">=</span> <span class="k">function</span> <span class="p">(</span><span class="n">r</span><span class="p">)</span> <span class="err">{</span>
  <span class="k">return</span> <span class="n">r</span><span class="p">.</span><span class="n">height</span> <span class="o">*</span> <span class="n">r</span><span class="p">.</span><span class="n">width</span><span class="p">;</span>
<span class="err">}</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>类定义里的代码都是在 strict mode
下执行，因此，如果类方法或实例方法执行的时候，没有被绑定的 this
不会指向全局对象，而是 undefined。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="n">Animal</span> { 
  <span class="n">speak</span>() {
    <span class="k">return</span> <span class="n">this</span>;
  }
  <span class="n">static</span> <span class="n">eat</span>() {
    <span class="k">return</span> <span class="n">this</span>;
  }
}

<span class="k">let</span> <span class="n">obj</span> = <span class="nb">new</span> <span class="n">Animal</span>();
<span class="n">obj</span>.<span class="n">speak</span>(); // <span class="n">Animal</span> {}
<span class="k">let</span> <span class="n">speak</span> = <span class="n">obj</span>.<span class="n">speak</span>;
<span class="n">speak</span>(); // <span class="n">undefined</span>

<span class="n">Animal</span>.<span class="n">eat</span>() // <span class="k">class</span> <span class="n">Animal</span>
<span class="k">let</span> <span class="n">eat</span> = <span class="n">Animal</span>.<span class="n">eat</span>;
<span class="n">eat</span>(); // <span class="n">undefined</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>和非 strict mode 下执行的下列代码作比较：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="k">function</span> <span class="n">Animal</span><span class="p">()</span> <span class="err">{</span> <span class="err">}</span>

<span class="n">Animal</span><span class="p">.</span><span class="n">prototype</span><span class="p">.</span><span class="n">speak</span> <span class="o">=</span> <span class="k">function</span><span class="p">()</span> <span class="err">{</span>
  <span class="k">return</span> <span class="n">this</span><span class="p">;</span>
<span class="err">}</span>

<span class="n">Animal</span><span class="p">.</span><span class="n">eat</span> <span class="o">=</span> <span class="k">function</span><span class="p">()</span> <span class="err">{</span>
  <span class="k">return</span> <span class="n">this</span><span class="p">;</span>
<span class="err">}</span>

<span class="n">let</span> <span class="n">obj</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Animal</span><span class="p">();</span>
<span class="n">let</span> <span class="n">speak</span> <span class="o">=</span> <span class="n">obj</span><span class="p">.</span><span class="n">speak</span><span class="p">;</span>
<span class="n">speak</span><span class="p">();</span> <span class="o">//</span> <span class="k">global</span> <span class="k">object</span>

<span class="n">let</span> <span class="n">eat</span> <span class="o">=</span> <span class="n">Animal</span><span class="p">.</span><span class="n">eat</span><span class="p">;</span>
<span class="n">eat</span><span class="p">();</span> <span class="o">//</span> <span class="k">global</span> <span class="k">object</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>在类里面还可以定义 getter 方法：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="n">Rectangle</span> {
  <span class="n">constructor</span>(<span class="n">height</span>, <span class="n">width</span>) {
    <span class="n">this</span>.<span class="n">height</span> = <span class="n">height</span>;
    <span class="n">this</span>.<span class="n">width</span> = <span class="n">width</span>;
  }

  <span class="n">calcArea</span>() {
    <span class="k">return</span> <span class="n">this</span>.<span class="n">height</span> * <span class="n">this</span>.<span class="n">width</span>;
  }

  <span class="n">get</span> <span class="n">area</span>() {
    <span class="k">return</span> <span class="n">this</span>.<span class="n">calcArea</span>();
  }
}
</code></pre></div>


<!-- /wp:code -->

<!-- wp:heading {"level":3} -->

<h3>属性定义</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->

<p>实例属性必须在构造函数或者实例方法中定义：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="err">class Rectangle {</span>
<span class="err">  constructor(height, width) {    </span>
<span class="err">    this.height = height;</span>
<span class="err">    this.width = width;</span>
<span class="err">  }</span>
<span class="err">}</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>而类属性和 prototype 属性只能在类定义之外定义：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="err">Rectangle.staticWidth = 20;</span>
<span class="err">Rectangle.prototype.prototypeWidth = 25;</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>在类里面可以定义私有实例属性，对于封装来说是一个好消息：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="err">class Rectangle {</span>
<span class="err">  #height = 0;</span>
<span class="err">  #width;</span>
<span class="err">  constructor(height, width) {    </span>
<span class="err">    this.#height = height;</span>
<span class="err">    this.#width = width;</span>
<span class="err">  }</span>
<span class="err">}</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:heading {"level":3} -->

<h3>继承</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->

<p>ES6类用 extends 继承已有的类：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="n">Animal</span> { 
  <span class="n">constructor</span>(<span class="nb">name</span>) {
    <span class="n">this</span>.<span class="nb">name</span> = <span class="nb">name</span>;
  }

  <span class="n">speak</span>() {
    <span class="n">console</span>.<span class="nb">log</span>(<span class="n">this</span>.<span class="nb">name</span> + <span class="s">&#39; makes a noise.&#39;</span>);
  }
}

<span class="k">class</span> <span class="n">Dog</span> <span class="n">extends</span> <span class="n">Animal</span> {
  <span class="n">constructor</span>(<span class="nb">name</span>) {
    <span class="n">super</span>(<span class="nb">name</span>); // <span class="n">call</span> <span class="n">the</span> <span class="n">super</span> <span class="k">class</span> <span class="n">constructor</span> <span class="o">and</span> <span class="nb">pass</span> <span class="n">in</span> <span class="n">the</span> <span class="nb">name</span> <span class="n">parameter</span>
  }

  <span class="n">speak</span>() {
    <span class="n">console</span>.<span class="nb">log</span>(<span class="n">this</span>.<span class="nb">name</span> + <span class="s">&#39; barks.&#39;</span>);
  }
}

<span class="k">let</span> <span class="n">d</span> = <span class="nb">new</span> <span class="n">Dog</span>(<span class="s">&#39;Mitzie&#39;</span>);
<span class="n">d</span>.<span class="n">speak</span>(); // <span class="n">Mitzie</span> <span class="n">barks</span>.
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>也可以直接继承用函数的方式定义的类：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="k">function</span> <span class="n">Animal</span> <span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="err">{</span>
  <span class="n">this</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="p">;</span>  
<span class="err">}</span>

<span class="n">Animal</span><span class="p">.</span><span class="n">prototype</span><span class="p">.</span><span class="n">speak</span> <span class="o">=</span> <span class="k">function</span> <span class="p">()</span> <span class="err">{</span>
  <span class="n">console</span><span class="p">.</span><span class="n">log</span><span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39; makes a noise.&#39;</span><span class="p">);</span>
<span class="err">}</span>

<span class="k">class</span> <span class="n">Dog</span> <span class="n">extends</span> <span class="n">Animal</span> <span class="err">{</span>
  <span class="n">speak</span><span class="p">()</span> <span class="err">{</span>
    <span class="n">console</span><span class="p">.</span><span class="n">log</span><span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39; barks.&#39;</span><span class="p">);</span>
  <span class="err">}</span>
<span class="err">}</span>

<span class="n">let</span> <span class="n">d</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Dog</span><span class="p">(</span><span class="s1">&#39;Mitzie&#39;</span><span class="p">);</span>
<span class="n">d</span><span class="p">.</span><span class="n">speak</span><span class="p">();</span> <span class="o">//</span> <span class="n">Mitzie</span> <span class="n">barks</span><span class="p">.</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>但要继承普通（没有构造功能的）对象，只能使用 Object.setPrototypeOf()：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="n">const</span> <span class="n">Animal</span> <span class="o">=</span> <span class="err">{</span>
  <span class="n">speak</span><span class="p">()</span> <span class="err">{</span>
    <span class="n">console</span><span class="p">.</span><span class="n">log</span><span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39; makes a noise.&#39;</span><span class="p">);</span>
  <span class="err">}</span>
<span class="err">}</span><span class="p">;</span>

<span class="k">class</span> <span class="n">Dog</span> <span class="err">{</span>
  <span class="k">constructor</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="err">{</span>
    <span class="n">this</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="p">;</span>
  <span class="err">}</span>
<span class="err">}</span>

<span class="o">//</span> <span class="k">If</span> <span class="n">you</span> <span class="k">do</span> <span class="k">not</span> <span class="k">do</span> <span class="n">this</span> <span class="n">you</span> <span class="n">will</span> <span class="k">get</span> <span class="n">a</span> <span class="n">TypeError</span> <span class="k">when</span> <span class="n">you</span> <span class="n">invoke</span> <span class="n">speak</span>
<span class="k">Object</span><span class="p">.</span><span class="n">setPrototypeOf</span><span class="p">(</span><span class="n">Dog</span><span class="p">.</span><span class="n">prototype</span><span class="p">,</span> <span class="n">Animal</span><span class="p">);</span>

<span class="n">let</span> <span class="n">d</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Dog</span><span class="p">(</span><span class="s1">&#39;Mitzie&#39;</span><span class="p">);</span>
<span class="n">d</span><span class="p">.</span><span class="n">speak</span><span class="p">();</span> <span class="o">//</span> <span class="n">Mitzie</span> <span class="n">makes</span> <span class="n">a</span> <span class="n">noise</span><span class="p">.</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:paragraph -->

<p>在子类中用 super() 调用父类的构造函数，用 super.method()
调用父类的实例方法：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code>class Cat { 
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`<span class="cp">${</span><span class="n">this</span><span class="o">.</span><span class="n">name</span><span class="cp">}</span> makes a noise.`);
  }
}

class Lion extends Cat {
  constructor(name) {
    super(name)
  }

  speak() {
    super.speak();
    console.log(`<span class="cp">${</span><span class="n">this</span><span class="o">.</span><span class="n">name</span><span class="cp">}</span> roars.`);
  }
}

let l = new Lion(&#39;Fuzzy&#39;);
l.speak(); 
// Fuzzy makes a noise.
// Fuzzy roars.
</code></pre></div>


<!-- /wp:code -->

<!-- wp:heading {"level":3} -->

<h3>实现混入（Mixin）</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->

<p>ES6
只支持类的单一继承，但由于类可以像普通变量一样被操作，实现混入也很容易：</p>
<!-- /wp:paragraph -->

<!-- wp:code -->

<div class="highlight"><pre><span></span><code><span class="n">let</span> <span class="n">calculatorMixin</span> <span class="o">=</span> <span class="n">Base</span> <span class="o">=&gt;</span> <span class="k">class</span> <span class="n">extends</span> <span class="n">Base</span> <span class="err">{</span>
  <span class="n">calc</span><span class="p">()</span> <span class="err">{</span> <span class="err">}</span>
<span class="err">}</span><span class="p">;</span>

<span class="n">let</span> <span class="n">randomizerMixin</span> <span class="o">=</span> <span class="n">Base</span> <span class="o">=&gt;</span> <span class="k">class</span> <span class="n">extends</span> <span class="n">Base</span> <span class="err">{</span>
  <span class="n">randomize</span><span class="p">()</span> <span class="err">{</span> <span class="err">}</span>
<span class="err">}</span><span class="p">;</span>

<span class="k">class</span> <span class="n">Foo</span> <span class="err">{</span> <span class="err">}</span>
<span class="k">class</span> <span class="n">Bar</span> <span class="n">extends</span> <span class="n">calculatorMixin</span><span class="p">(</span><span class="n">randomizerMixin</span><span class="p">(</span><span class="n">Foo</span><span class="p">))</span> <span class="err">{</span> <span class="err">}</span>
</code></pre></div>


<!-- /wp:code -->

<!-- wp:heading -->

<h2>参考资料</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->

<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">MDN
文档：classes</a></p>
<!-- /wp:paragraph -->
    </div>
<nav class="nav sidebar">
    <div class="siteinfo">
        <div class="sitename"><a href="..">coinfaces</a></div>
        <div class="tagline">Another Side of Life</div>
    </div>

        <a href="../categories/">categories</a>
        <a href="..">&larr; Home</a>
</nav><footer class="footer">
    <span>
        &copy; jpli &middot;
        under <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">CC-BY-SA 4.0</a>
    </span>
    |
    <span>
        Powered by:
        <a href="http://blog.getpelican.com/">Pelican</a>
    </span>
</footer></body>
</html>